#include <iostream>
#include "String.h"
#include <cassert>

using namespace std;

String::String(){
	/* * 
	_string = "";
	* */
	_size = 0;
	_string = 0;

}

String::String(const char *chars){
	/* *
	_string = chars;
	* */
	if(!chars){
		_size = 0;
		_string = 0;
	}
	else{
		_size = strlen(chars);
		_string = new char[_size + 1];
		strcpy(_string, chars);
	}
}

String::String(const String &string){
	/* *
	_string = string.c_str();
	* */
	_size = string._size;
	if(!string._string)
		_string = 0;
	else{
		_string = new char[_size + 1];
		strcpy(_string, string._string);
	}
}

String::~String(){
	_size = 0;
	delete [] _string;
	_string = 0;
}

String& String::operator=(const String &string){
	/* *
	_string = string.c_str();
	return *this;
	* */
	if(this != &string)
	{
		delete [] _string;
		_size = string._size;
		// char* s = string.c_str(); // const object cannot access non-const function, error: IntelliSense: the object has type qualifiers that are not compatible with the member function

		if(!string._string)
			_string = 0;
		else{
			_string = new char[_size + 1];
			strcpy(_string, string._string);
		}
	}
	return *this;
}

String& String::operator=(const char *chars){
	/* *
	_string = chars;
	return *this;
	* */
	if(!chars){
		_size = 0;
		delete[] _string;
		_string = 0;
	}
	else{
		_size = strlen(chars);
		delete[] _string;
		_string = new char[_size + 1];
		strcpy(_string, chars);
	}
	return *this;
}

String String::operator+(const String &string){
	if(0 == string._size || 0 == string._string)
		return *this;
	
	String str;
	str._size = _size + string._size;
	str._string = new char[str._size + 1];
	memset(str._string, '\0', str._size + 1); // init the memory!!
	/*strcpy(str._string, _string);
	strcpy(str._string + _size, string._string);*/
	strcat(str._string, _string); // strcat, will search the '\0' in the string to indicate the location to add the string.
	strcat(str._string, string._string); /**/	
	_size += string._size;
	strcat(_string, string._string);
	// str._string = strcat(_string, string._string);   

	return str;
}

bool String::operator==(const String &string){
	/* *
	if(_string == string.c_str())
		return true;
	else
		return false;
		* */
	if(_size != string._size) // Why cannot access string._size dirrectly here??
		return false;
	return strcmp(_string, string._string) ? false : true;
}

bool String::operator==(const char *chars){
	/* *
	if(_string == chars)
		return true;
	else
		return false;
		* */
	return strcmp(_string, chars) ? false : true;
}

char& String::operator[](int index){
	/* *
	char ch = ' ';
	if(_size <=  index)
		return ch;
	return *(_string + index);
	* */
	assert(index >= 0 && index < _size);
	return _string[index];
}

#include <iomanip>

istream& operator>>(istream &io, String &s){	
	char inBuf[ LIMIT_STRING_SIZE];
	io >> setw( LIMIT_STRING_SIZE) >> inBuf;
	s = inBuf; // String::operator=(const char*);

	return io;
}

ostream& operator<<(ostream &os, String &s){
	return os << s.c_str();
}

#define _DYNAMIC_CREATE(objectPointer, className, parameter) \
	objectPointer = new className(#parameter);


void StringTest(){
	String str;
	String str1("abcd");
	str = "abcd";
	cout << str << endl;
	/*
	String str2 = "Why";
	String &strRef = str2;
	cout << strRef._string << endl; // Why cannot access _string here? but String& String::operator=(const String &string) can ??
	*/

	String s1("abc");
	String s2("123");
	String s3 = s1 + s2;

	cout << "s3: " << s3 << endl;


	if(str == str1)
		cout << "Equal" << endl;

	cin >> str;
	cout << "string you input: " << str << endl;
	
	void *objPtr;
	_DYNAMIC_CREATE(objPtr, String, abc)

	cout << ((String*)objPtr)->size();
}